/*
* Copyright (c) 2014 Razeware LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

import CoreData

public class CoreDataStack {
  
  let context:NSManagedObjectContext
  let psc:NSPersistentStoreCoordinator
  let model:NSManagedObjectModel
  var store:NSPersistentStore?
  
  public init() {
    
    let modelName = "SurfJournalModel"
    let databaseName = "SurfJournalDatabase.sqlite"
    
    let bundle = NSBundle.mainBundle()
    let modelURL =
      bundle.URLForResource(modelName, withExtension:"momd")
    model = NSManagedObjectModel(contentsOfURL: modelURL!)!
    
    psc =
      NSPersistentStoreCoordinator(managedObjectModel:model)
    
    context = NSManagedObjectContext(
      concurrencyType: .MainQueueConcurrencyType)
    context.persistentStoreCoordinator = psc
    
    let documentsURL = applicationDocumentsDirectory()
    let storeURL =
      documentsURL.URLByAppendingPathComponent(databaseName)
    
		/*
		1.The app bundle comes with a pre-populated Core Data database named SurfJournalDatabase.sqlite. To make use of this database, first you have to find it and create a URL reference to it using URLForResource(_:withExtension:).
		2.copyItemAtURL(_:toURL:error:) attempts to copy the seeded database file to the app’s documents directory. If the database file already exists in the documents directory, the copy operation fails. This behavior allows the seeding operation to happen only once, on first launch.
		3.On subsequent app launches, the database will already exist and the copy will fail. When the copy operation fails, the variable didCopyDatabase will be false and the code in the if-statement will never execute.
		*/
    // 1
    let seededDatabaseURL = bundle
      .URLForResource("SurfJournalDatabase",
        withExtension: "sqlite")
    
    // 2
    var fileManagerError:NSError? = nil
    let didCopyDatabase = NSFileManager.defaultManager()
      .copyItemAtURL(seededDatabaseURL!, toURL: storeURL,
        error: &fileManagerError)
    
    // 3
    if didCopyDatabase {
			/*
			To support concurrent reads and writes, SQLite, the persistent store in use by this sample app, utilizes SHM (shared memory file) and WAL (write-ahead logging) files. 
			You don’t need to know how these extra files work, but you do need to be aware that they exist and that you need to copy them over when seeding the database. If you fail to copy over these files, the app will work, but it will be missing data.
			*/
			/*
			4.Once the initializer has successfully copied the primary SurfJournalDatabase.sqlite, it copies over the support file SurfJournalDatabase.sqlite-shm.
			5.Finally, the initializer copies over the other support file, SurfJournalDatabase.sqlite-wal.
			*/
      // 4
      fileManagerError = nil
      let seededSHMURL = bundle
        .URLForResource("SurfJournalDatabase",
          withExtension: "sqlite-shm")
      let shmURL = documentsURL.URLByAppendingPathComponent(
        "SurfJournalDatabase.sqlite-shm")
      
      let didCopySHM = NSFileManager.defaultManager()
        .copyItemAtURL(seededSHMURL!, toURL: shmURL,
          error: &fileManagerError)
      if !didCopySHM {
        println("Error seeding Core Data: \(fileManagerError)")
        abort()
      }
      
      // 5
      fileManagerError = nil
      let walURL = documentsURL.URLByAppendingPathComponent(
        "SurfJournalDatabase.sqlite-wal")
      let seededWALURL = bundle
        .URLForResource("SurfJournalDatabase",
          withExtension: "sqlite-wal")
      
      let didCopyWAL = NSFileManager.defaultManager()
        .copyItemAtURL(seededWALURL!, toURL: walURL,
          error: &fileManagerError)
      if !didCopyWAL {
        println("Error seeding Core Data: \(fileManagerError)")
        abort()
      }
      
      println("Seeded Core Data")
    }
    
		/*
		Once the initializer has copied over the pre-populated database and support files, the final step is to add the seeded database store to the persistent store coordinator.
		*/
		/*
		6.NSPersistentStoreCoordinator hands you an NSPersistentStore object as a side effect of attaching a persistent store type. You simply have to specify the store type (NSSQLiteStoreType in this case), the URL location of the store file and some configuration options.
		7.Finally, the initializer checks if the store was successfully created. If it wasn’t, the app won’t work, so there’s no point in continuing; the initializer calls abort.
		*/
    // 6
    var error: NSError? = nil
    let options = [NSInferMappingModelAutomaticallyOption:true,
      NSMigratePersistentStoresAutomaticallyOption:true]
    store = psc.addPersistentStoreWithType(NSSQLiteStoreType,
      configuration: nil,
      URL: storeURL,
      options: options,
      error: &error)

    // 7
    if store == nil {
      println("Error adding persistent store: \(error)")
      abort()
    }
  }
  
  func applicationDocumentsDirectory() -> NSURL {
  
    let fileManager = NSFileManager.defaultManager()
  
    let urls =
      fileManager.URLsForDirectory(.DocumentDirectory,
        inDomains: .UserDomainMask) as! [NSURL]
  
    return urls[0]
  }
  
  func saveContext() {
    context.performBlock { () -> Void in
      var error: NSError? = nil
      if self.context.hasChanges && !self.context.save(&error) {
        println("Could not save: \(error), \(error?.userInfo)")
        abort()
      }
    }
  }
  
}

